package com.lz.ub

import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.util.ArrayMap
import com.lz.ub.core.RFMainReader
import com.lz.ub.core.UBCCallbackHandler
import com.lz.ub.core.UBCScanResult

/**
 * @author You
 * 核心UBCDispatcher管理类
 */
class UBCManager private constructor(
    private val usbManager: UsbManager,
    private val baudRate: Int,
    private val dataBits: Int,
    private val stopBits: Int,
    private val parity: Int,
    private val readerFactory: UBCReader.Factory,
    callbackFactory: UBCCallbackExecute.Factory
) : UBCCallback, UBCScanCallback {
    companion object {
        const val TAG = "UBCManager"

        //instance
        private var INSTANCE: UBCManager? = null

        internal fun init(
            usbManager: UsbManager,
            baudRate: Int = UBC_BAUD_RATE,
            dataB: Int = UBC_DATA_BITS,
            stopB: Int = UBC_STOP_BITS,
            parity: Int = UBC_PARITY,
            readerFactory: UBCReader.Factory = ReaderFactory(),
            callbackFactory: UBCCallbackExecute.Factory = CallbackFactory()
        ) {
            if (INSTANCE == null) INSTANCE = UBCManager(usbManager,
                baudRate, dataB, stopB, parity, readerFactory, callbackFactory)
        }

        fun get(): UBCManager {
            if (INSTANCE == null) throw IllegalStateException("You need init(context) first")
            return INSTANCE!!
        }
    }

    //当前可用的USB设备
    private val usbDevices = ArrayMap<Int, UBCDispatcher>()

    //当前已经绑定UsbDevice的调度器
//    private val usbDevices = ArrayMap<String, UBCDispatcher>(MAX_USB_DEVICE_SIZE)

    //回调线程切换器
    private val callbackExecute: UBCCallbackExecute

    //回调
    private val callbacks = ArrayList<UBCCallback>()

    //扫描回调
    private val scanCallbacks = ArrayList<UBCScanCallback>()

    init {
        callbackExecute = callbackFactory.create(this, this)
    }

    fun isOpened(): Boolean {
        for (dispatcher in usbDevices.values) {
            if (dispatcher.isOpened()) return true
        }
        Logger.d(TAG, "****** isOpened false ${usbDevices.values.size} ******")
        return false
    }

    fun restartAssist() {
        usbDevices.forEach { (_, dispatcher) -> if (dispatcher.isAssistDispatcher) dispatcher.restart() }
    }

    fun restart() {
        Logger.i(TAG, "****** ———————————— restart  ———————————— ******")
        usbDevices.forEach { (_, dispatcher) -> if (!dispatcher.isAssistDispatcher) dispatcher.restart() }
    }

    fun scan() {
        for (dispatcher in usbDevices.values) {
            if (dispatcher.isOpened()) {
                dispatcher.scan()
                break
            }
        }
    }

    fun stopScan() {
        for (dispatcher in usbDevices.values) {
            if (dispatcher.isOpened()) {
                dispatcher.stopScan()
                break
            }
        }
    }

    fun close() {
        usbDevices.forEach { (_, dispatcher) -> dispatcher.close() }
    }

    fun addDevice(mac: String, w_num: Int, r_num: Int, isAuto: Boolean = true, tag: Any? = null): Boolean {
        for (dispatcher in usbDevices.values) {
            if (!dispatcher.isAssistDispatcher && dispatcher.addUBCDevice(mac, w_num, r_num, isAuto, tag))
                return true
        }
        return false
    }

    fun addDevice(deviceList: MutableList<UBCDevice>) {
        for (dispatcher in usbDevices.values) {
            if (dispatcher.isAssistDispatcher) continue
            if (!dispatcher.addUBCDeviceList(deviceList)) break
        }
    }

    //连接所有设备, 包括辅助设备
    fun connectAssist() {
        usbDevices.forEach { (_, dispatcher) -> if (dispatcher.isAssistDispatcher) dispatcher.connect() }
    }

    //连接设备
    fun connect() {
        usbDevices.forEach { (_, dispatcher) -> if (!dispatcher.isAssistDispatcher) dispatcher.connect() }
    }

    //断开不清空
    fun disconnect() {
        usbDevices.forEach { (_, dispatcher) -> if (!dispatcher.isAssistDispatcher) dispatcher.disconnect() }
    }

    //断开清空连接设备
    fun clear() {
        usbDevices.forEach { (_, dispatcher) -> if (!dispatcher.isAssistDispatcher) dispatcher.clear() }
    }

    //取消清空重连并断开所有
    fun cancelAndClearAuto() {
        usbDevices.forEach { (_, dispatcher) -> if (!dispatcher.isAssistDispatcher) dispatcher.cancelAndClearAuto() }
    }

    //16进制的数据都是针对从设备非辅助设备, 所有连接设备发送
    fun pushHexCommand(hexCommand: String, timeout: Int = COMMAND_WRITE_TIMEOUT) {
        usbDevices.forEach { (_, dispatcher) ->
            if (!dispatcher.isAssistDispatcher) dispatcher.pushHexCommand(hexCommand, timeout)
        }
    }

    //16进制的数据都是针对从设备非辅助设备, 单独一台发送
    fun pushHexCommand(mac: String, hexCommand: String, timeout: Int = COMMAND_WRITE_TIMEOUT) {
        usbDevices.forEach { (_, dispatcher) ->
            if (!dispatcher.isAssistDispatcher) dispatcher.pushHexCommand(mac, hexCommand, timeout)
        }
    }

    //16进制的数据都是针对从设备非辅助设备, 多台发送
    fun pushHexCommand(macs: List<String>, hexCommand: String, timeout: Int = COMMAND_WRITE_TIMEOUT) {
        usbDevices.forEach { (_, dispatcher) ->
            if (!dispatcher.isAssistDispatcher) dispatcher.pushHexCommand(macs, hexCommand, timeout)
        }
    }

    fun addUBCCallback(callback: UBCCallback) {
        callbacks.add(callback)
    }

    fun removeUBCCallback(callback: UBCCallback) {
        callbacks.remove(callback)
    }

    fun addUBCScanCallback(callback: UBCScanCallback) {
        scanCallbacks.add(callback)
    }

    fun removeUBCScanCallback(callback: UBCScanCallback) {
        scanCallbacks.remove(callback)
    }

    //找出辅助设备
    private fun findAssistDispatcher(): UBCDispatcher? {
        for (dispatcher in usbDevices.values) {
            if (dispatcher.isAssistDispatcher) return dispatcher
        }
        return null
    }

    //插入USB设备
    fun addUsbDevice(device: UsbDevice) {
        if (usbDevices.contains(device.deviceId)) {
            Logger.d(TAG, "******add usbDevice (name = ${device.deviceId}) but it has exist ******")
            return
        }
        //暂不支持辅助设备
        val dispatcher = UBCDispatcher(
            device, usbManager, baudRate, dataBits, stopBits, parity,
            readerFactory, false, callbackExecute
        )
        dispatcher.start()
        usbDevices[device.deviceId] = dispatcher
/*        if (usbDevices.size >= MAX_USB_DEVICE_SIZE) {
            Logger.d(TAG, "******add usbDevice (name = ${device.deviceId}) but it has full ******")
            return
        }
        //已经有了辅助设备 或者 没有辅助设备
        val isAssistDispatcher = findAssistDispatcher() == null && usbDevices.size >= MAX_USB_DEVICE_SIZE - 1
        val dispatcher = UBCDispatcher(
            device, usbManager, baudRate, dataBits, stopBits, parity,
            readerFactory, isAssistDispatcher, callbackExecute
        )
        dispatcher.start()
        usbDevices[device.deviceName] = dispatcher*/
    }

    //拔出USB设备
    fun removeUsbDevice(device: UsbDevice) {
        Logger.d(TAG, "******removeUsbDevice (name = ${device.deviceId}) *****")
        val dispatcher = usbDevices.remove(device.deviceId) ?: return
        dispatcher.close()
    }

    override fun onConnected(device: UBCDevice, isAssist: Boolean) {
        callbacks.forEach { it.onConnected(device, isAssist) }
    }

    override fun onDisconnected(device: UBCDevice, isAssist: Boolean) {
        callbacks.forEach { it.onDisconnected(device, isAssist) }
    }

    override fun onReadHex(device: UBCDevice, bytes: ByteArray, start: Int, size: Int, isAssist: Boolean) {
        callbacks.forEach { it.onReadHex(device, bytes, start, size, isAssist) }
    }

    override fun onRead(device: UBCDevice, data: String, isAssist: Boolean) {
        callbacks.forEach { it.onRead(device, data, isAssist) }
    }

    override fun onScanResult(result: UBCScanResult) {
        scanCallbacks.forEach { it.onScanResult(result) }
    }

    //默认工厂类, 也可自己实现一套解析机制
    private class ReaderFactory : UBCReader.Factory {

        override fun create(execute: UBCExecute, tag: Any?): UBCReader = RFMainReader(execute, tag)
    }

    //默认回调工厂类
    private class CallbackFactory : UBCCallbackExecute.Factory {
        override fun create(callback: UBCCallback, scanCallback: UBCScanCallback): UBCCallbackExecute {
            return UBCCallbackHandler(callback, scanCallback)
        }
    }
}